package com.onlyxiahui.extend.query.hibernate.handler;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
//import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.Parameter;
import javax.persistence.Query;

//import org.hibernate.hql.spi.FilterTranslator;
//import org.hibernate.hql.spi.QueryTranslatorFactory;
//import org.hibernate.internal.SessionImpl;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.internal.NativeQueryImpl;
import org.hibernate.transform.Transformers;

import com.onlyxiahui.extend.query.hibernate.QueryWrapper;
import com.onlyxiahui.extend.query.hibernate.handler.result.ResultToBean;
import com.onlyxiahui.extend.query.hibernate.handler.result.ResultType;
import com.onlyxiahui.extend.query.page.QueryPage;

/**
 * Date 2018-12-28 15:51:20<br>
 * Description
 *
 * @author XiaHui<br>
 * @since 1.0.0
 */
public class JpaHandler extends BaseHandler {

//	public String hql2Sql(EntityManager session,String hql) {
//		if (session != null && session instanceof SessionImpl) {
//			SessionImpl si = (SessionImpl) session;
//			QueryTranslatorFactory qtf = sfi.getSettings().getQueryTranslatorFactory();
//			Map enableFilters = si.getEnabledFilters();
//			if (enableFilters == null) {
//				enableFilters = Collections.EMPTY_MAP;
//			}
//			FilterTranslator qt = qtf.createFilterTranslator(hql, hql, enableFilters, sfi);
//			qt.compile(enableFilters, false);
//
//			String sql = qt.getSQLString();
//
//			return sql;
//		}
// 
//		return null;
// 
//	}
	public void setParameter(Query query, QueryWrapper queryWrapper) {
		if (queryWrapper != null) {
			Map<String, Object> map = queryWrapper.getParameterMap();
			Set<Parameter<?>> manes = query.getParameters();
			for (Parameter<?> p : manes) {
				String name = p.getName();
				Object value = map.get(name);
				if (value instanceof Collection) {
					query.setParameter(name, (Collection<?>) value);
				} else if (value instanceof Object[]) {
					query.setParameter(name, (Object[]) value);
				} else {
					query.setParameter(name, value);
				}
			}
		}
	}

	public void setScalar(Query query, List<ResultType> returnTypeList) {
		if (returnTypeList != null && returnTypeList.size() > 0) {
			if (query instanceof NativeQuery) {
				NativeQuery<?> nativeQuery = (NativeQuery<?>) query;
				for (ResultType returnType : returnTypeList) {
					if (returnType.getReturnType() != null) {
						nativeQuery.addScalar(returnType.getColumnName(), returnType.getReturnType());
					} else {
						nativeQuery.addScalar(returnType.getColumnName());
					}
				}
			}
		}
	}

	public Query createHqlQuery(EntityManager session, String hql) {
		Query query = session.createQuery(hql);
		return query;
	}

	public Query createSqlQuery(EntityManager session, String sql) {
		Query query = session.createNativeQuery(sql);
		return query;
	}

	public int getCount(Query query) {
		int count = 0;
		Object o = query.getSingleResult();
		if (o instanceof Long) {
			count = ((Long) o).intValue();
		} else if (o instanceof BigInteger) {
			count = ((BigInteger) o).intValue();
		} else if (o instanceof Integer) {
			count = ((Integer) o);
		}
		return count;
	}

	public int updateBySql(EntityManager session, String sql, QueryWrapper queryWrapper) {
		Query query = createSqlQuery(session, sql);
		setParameter(query, queryWrapper);
		int count = query.executeUpdate();
		return count;
	}

	@SuppressWarnings("unchecked")
	public <T> T queryObjectBySql(EntityManager session, String sql, QueryWrapper queryWrapper, Class<T> resultClass, List<ResultType> returnTypeList) {

		Query query = createSqlQuery(session, sql);
		setParameter(query, queryWrapper);
		setScalar(query, returnTypeList);
		if (resultClass != null && !this.isPrimitive(resultClass) && !this.isString(resultClass)) {
			if (null == returnTypeList || returnTypeList.isEmpty()) {
				query.unwrap(NativeQueryImpl.class).setResultTransformer(new ResultToBean(resultClass));
			} else {
				query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.aliasToBean(resultClass));
			}
		} else if (null == resultClass) {
			query.unwrap(NativeQueryImpl.class).setResultTransformer(new ResultToBean(resultClass));
		}
		Object value = null;
		// query.getSingleResult();
		List<?> list = query.getResultList();
		if (null != list && !list.isEmpty()) {
			value = list.get(0);
		}
		if (value instanceof BigInteger) {
			if (Long.class == resultClass) {
				value = ((BigInteger) value).longValue();
			}
		}
		return (T) value;
	}

	public <T> List<T> queryListBySql(EntityManager session, String sql, QueryWrapper queryWrapper, Class<?> resultClass, List<ResultType> returnTypeList) {
		this.queryResultCountBySql(session, sql, queryWrapper);
		List<T> list = this.queryResultListBySql(session, sql, queryWrapper, resultClass, returnTypeList);
		return list;
	}

	public int queryResultCountBySql(EntityManager session, String sql, QueryWrapper queryWrapper) {
		QueryPage page = queryWrapper.getPage();
		int totalCount = 0;
		if (null != page) {
			String queryCountSql = wrapTotalSql(sql);
			Query queryCount = createSqlQuery(session, queryCountSql);
			setParameter(queryCount, queryWrapper);
			totalCount = getCount(queryCount);
			page.setTotalCount(totalCount);
		}
		return totalCount;
	}

	@SuppressWarnings("unchecked")
	public <T> List<T> queryResultListBySql(EntityManager session, String sql, QueryWrapper queryWrapper, Class<?> resultClass, List<ResultType> returnTypeList) {

		QueryPage page = queryWrapper.getPage();
		List<?> list = null;
		boolean doQuery = true;
		if (null != page) {
			doQuery = page.getPageSize() > 0;
		}

		if (doQuery) {
			Query query = createSqlQuery(session, sql);
			if (null != page) {
				query.setFirstResult(page.getStartResult());
				query.setMaxResults(page.getPageSize());
			}
			setParameter(query, queryWrapper);
			if (resultClass != null && !this.isPrimitive(resultClass) && !this.isString(resultClass)) {
				if (null == returnTypeList || returnTypeList.isEmpty()) {
					query.unwrap(NativeQueryImpl.class).setResultTransformer(new ResultToBean(resultClass));
				} else {
					query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.aliasToBean(resultClass));
				}
			} else if (null == resultClass) {
				query.unwrap(NativeQueryImpl.class).setResultTransformer(new ResultToBean(resultClass));
			}
			list = query.getResultList();
		}
		if (null == list) {
			list = new ArrayList<>();
		}
		if (null != page) {
			page.setResultList(list);
		}
		return (List<T>) list;
	}

	/*****************************************************/

	public int updateByHql(EntityManager session, String hql, QueryWrapper queryWrapper) {
		Query query = createHqlQuery(session, hql);
		setParameter(query, queryWrapper);
		int count = query.executeUpdate();
		return count;
	}

	@SuppressWarnings("unchecked")
	public <T> T queryObjectByHql(EntityManager session, String hql, QueryWrapper queryWrapper, Class<T> resultClass) {
		Query query = createHqlQuery(session, hql);
		setParameter(query, queryWrapper);
		Object value = null;
		// query.getSingleResult();
		List<?> list = query.getResultList();
		if (null != list && !list.isEmpty()) {
			value = list.get(0);
		}
		if (value != null && value instanceof Map && !Map.class.isAssignableFrom(resultClass)) {
			value = mapToObject((Map<String, Object>) value, resultClass);
		}
		return (T) value;
	}

	@SuppressWarnings("unchecked")
	public <T> List<T> queryListByHql(EntityManager session, String hql, QueryWrapper queryWrapper, Class<?> resultClass) {
		this.queryResultCountByHql(session, hql, queryWrapper);
		List<?> list = this.queryResultListByHql(session, hql, queryWrapper, resultClass);
		return (List<T>) list;
	}

	public int queryResultCountByHql(EntityManager session, String hql, QueryWrapper queryWrapper) {
		QueryPage page = queryWrapper.getPage();
		int totalCount = 0;
		if (null != page) {
			String queryCountSql = wrapTotalHql(hql);
			Query queryCount = createHqlQuery(session, queryCountSql);
			setParameter(queryCount, queryWrapper);
			totalCount = getCount(queryCount);
			page.setTotalCount(totalCount);
		}
		return totalCount;
	}

	@SuppressWarnings("unchecked")
	public <T> List<T> queryResultListByHql(EntityManager session, String hql, QueryWrapper queryWrapper, Class<?> resultClass) {

		QueryPage page = queryWrapper.getPage();
		List<?> list = null;

		boolean doQuery = true;
		if (null != page) {
			doQuery = page.getPageSize() > 0;
		}
		if (doQuery) {
			Query query = createHqlQuery(session, hql);
			if (null != page) {
				query.setFirstResult(page.getStartResult());
				query.setMaxResults(page.getPageSize());
			}
			setParameter(query, queryWrapper);
			list = query.getResultList();
		}
		if (null == list) {
			list = new ArrayList<>();
		}
		int size = list.size();
		if (size > 0 && (list.get(0) instanceof Map) && !Map.class.isAssignableFrom(resultClass)) {
			List<Object> t = new ArrayList<>(size);
			// 当list的第一个对象是Map时才转换
			Map<String, Object> map = null;
			for (int i = 0; i < size; i++) {
				map = (Map<String, Object>) list.get(i);
				if (map != null) {
					t.add(mapToObject((Map<String, Object>) map, resultClass));
				}
			}
			list = t;
		}
		if (null != page) {
			page.setResultList(list);
		}
		return (List<T>) list;
	}
}
